﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CCodeTreeLib;
using SqlOrm.Xml;

namespace SqlOrm.TreeBuilders
{
    public class UIEntitiesTreeBuilder : CCodeTree
    {
        DataDictionary _ddl;
        public UIEntitiesTreeBuilder(DataDictionary ddl)
        {
            _ddl = ddl;
            Build();
        }
        void Build()
        {
            Console.WriteLine("Building UI entities...");
            this.Usings.Add(new CCodeUsing("System"));
            this.Usings.Add(new CCodeUsing("System.ComponentModel"));
            var ns = AddStatement(new CCodeNamespace(_ddl.Settings.EntitiesOutput.clrnamespace));
            if (_ddl.Definition.Schema != null)
            {
                foreach (var table in _ddl.Definition.Schema.Table)
                {
                    var cls = new CCodeClass(table.ClassName + "Entity") { Modifier = Modifier.Public };
                    cls.ImplementedInterfaces.Add("INotifyPropertyChanged");
                    cls.AddStatement(new CCodeEventDeclaration("PropertyChangedEventHandler", "PropertyChanged"));
                    foreach (var f in table.Field)
                    {
                        var p = cls.CreateProperty(f.ClrDataType, f.title, true);
                        p.AddSetStatement("PropertyChanged(this, new PropertyChangedEventArgs(\"" + f.title + "\"));");
                    }
                    //Console.WriteLine("Entity: " + cls.Name);
                    ns.AddStatement(cls);
                }
            }
            if (_ddl.Definition.Procedures != null)
            {
                foreach (var proc in _ddl.Definition.Procedures)
                {
                    var nfGroupedByTypeName = proc.NestedFields.GroupBy(x => x, n => n.Field, (k, f) => new { Key = k, Fields = f }, new NestedFieldComparer()).Where(x => x.Key.NestedClassName != null);
                    if (nfGroupedByTypeName.Count() > 0)
                    {
                        foreach (var g in nfGroupedByTypeName)
                        {
                            if (!_ddl.Definition.Schema.Table.Any(x => x.ClassName == g.Key.NestedType))
                            {
                                var cls = new CCodeClass(g.Key + "Entity");
                                cls.ImplementedInterfaces.Add("INotifyPropertyChanged");
                                cls.Modifier = Modifier.Public;
                                foreach (var f in g.Fields)
                                {
                                    var p = cls.CreateProperty(f.ClrDataType, f.title, true);
                                    p.AddSetStatement("PropertyChanged(this, new PropertyChangedEventArgs(\"" + f.title + "\"));");
                                }
                                ns.AddStatement(cls);
                            }
                        }
                    }
                    if (proc.OutputType == ProcedureOutputType.Custom)
                    {
                        var cls = new CCodeClass(proc.name + "OutputEntity");
                        cls.ImplementedInterfaces.Add("INotifyPropertyChanged");
                        cls.AddStatement(new CCodeEventDeclaration("PropertyChangedEventHandler", "PropertyChanged"));
                        cls.Modifier = Modifier.Public;
                        foreach (var f in proc.NestedFields.Where(x => x.NestedClassName == null).Select(x => x.Field))
                        {
                            var p = cls.CreateProperty(f.ClrDataType, f.title, true);
                            p.AddSetStatement("PropertyChanged(this, new PropertyChangedEventArgs(\"" + f.title + "\"));");
                        }
                        //Console.WriteLine("Entity: " + cls.Name);
                        ns.AddStatement(cls);
                    }
                }
            }
        }
    }
}
